package org.easy.miniooss;

import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.PutObjectOptions;
import io.minio.errors.*;
import org.springframework.lang.Nullable;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * OssClientAdapter  与 Minio 的适配器
 *
 * @author: Li chaojie
 * @Date: 2022/7/4
 * @Description:
 */
public class MinioOssAdapter implements OssClientAdapter {


    public MinioClient getMinioClient(OssBaseProperties ossBaseProperties, String endpoint) {
        if (endpoint == null) {
            try {
                return new MinioClient(ossBaseProperties.getEndpoint(), ossBaseProperties.getAccessKeyId(), ossBaseProperties.getAccessKeySecret());
            } catch (InvalidEndpointException | InvalidPortException e) {
                throw new MinioAdapterException(e.toString(), e);
            }
        } else {
            try {
                return new MinioClient(endpoint, ossBaseProperties.getAccessKeyId(), ossBaseProperties.getAccessKeySecret());
            } catch (InvalidEndpointException | InvalidPortException e) {
                throw new MinioAdapterException(e.toString(), e);
            }
        }
    }


    @Override
    public FileOutDto upload(OssBaseProperties ossBaseProperties, String bucket, String ossKey, InputStream inputStream, @Nullable Long objectSize) {
        if (objectSize == null) {
            objectSize = -1L;
        }
        try {
            // 使用MinIO服务的URL，端口，Access key和Secret key创建一个MinioClient对象
            MinioClient minioClient = getMinioClient(ossBaseProperties, null);

            // 检查存储桶是否已经存在
            boolean isExist = minioClient.bucketExists(bucket);
            if (!isExist) {
                minioClient.makeBucket(bucket);
            }

            // 使用putObject上传一个文件到存储桶中。
            try (InputStream is = inputStream) {
                minioClient.putObject(bucket, ossKey, is, new PutObjectOptions(objectSize, PutObjectOptions.MAX_PART_SIZE));
            }

            FileOutDto fileOutDto = new FileOutDto();
            fileOutDto.setFilePath(ossBaseProperties.getProtocol() + "://" + ossBaseProperties.getEndpoint() + "/" + bucket + "/" + ossKey);
            fileOutDto.setBucket(bucket);
            fileOutDto.setEndpoint(ossBaseProperties.getEndpoint());
            fileOutDto.setKey(ossKey);
            return fileOutDto;
        } catch (MinioException | IOException | NoSuchAlgorithmException | InvalidKeyException e) {
            throw new MinioAdapterException(e.toString(), e);
        }
    }

    @Override
    public FileOutDto upload(OssBaseProperties ossBaseProperties, String bucket, String ossKey, InputStream inputStream, Long objectSize, String endpoint) {
        if (objectSize == null) {
            objectSize = -1L;
        }
        try {
            // 使用MinIO服务的URL，端口，Access key和Secret key创建一个MinioClient对象
            MinioClient minioClient = getMinioClient(ossBaseProperties, endpoint);

            // 检查存储桶是否已经存在
            boolean isExist = minioClient.bucketExists(bucket);
            if (!isExist) {
                minioClient.makeBucket(bucket);
            }

            // 使用putObject上传一个文件到存储桶中。
            try (InputStream is = inputStream) {
                minioClient.putObject(bucket, ossKey, is, new PutObjectOptions(objectSize, PutObjectOptions.MAX_PART_SIZE));
            }

            FileOutDto fileOutDto = new FileOutDto();
            fileOutDto.setFilePath(ossBaseProperties.getProtocol() + "://" + ossBaseProperties.getEndpoint() + "/" + bucket + "/" + ossKey);
            fileOutDto.setBucket(bucket);
            fileOutDto.setEndpoint(ossBaseProperties.getEndpoint());
            fileOutDto.setKey(ossKey);
            return fileOutDto;
        } catch (MinioException | IOException | NoSuchAlgorithmException | InvalidKeyException e) {
            throw new MinioAdapterException(e.toString(), e);
        }
    }

    @Override
    public String getPublicUrl(OssBaseProperties ossBaseProperties, String bucket, String ossKey) {
        return ossBaseProperties.getEndpoint() + "/" + bucket + "/" + ossKey;
    }

    @Override
    public String getPublicUrl(String protocol, String bucket, String ossKey, String endpoint) {
        return null;
    }

    @Override
    public String getPresignedUrl(OssBaseProperties ossBaseProperties, String bucket, String ossKey, @Nullable Integer expires) {
        if (expires == null) {
            expires = 7 * 24 * 3600;
        }
        try {
            // 使用MinIO服务的URL，端口，Access key和Secret key创建一个MinioClient对象
            return getMinioClient(ossBaseProperties, null).presignedGetObject(bucket, ossKey, expires, null);
        } catch (MinioException | IOException | NoSuchAlgorithmException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String getPresignedUrl(OssBaseProperties ossBaseProperties, String endpoint, String bucket, String ossKey, Integer expires) {
        return null;
    }

    @Override
    public Boolean isExitsObject(OssBaseProperties ossBaseProperties, String bucket, String ossKey) {
        try {
            MinioClient minioClient = getMinioClient(ossBaseProperties, null);
            ObjectStat objectStat = minioClient.statObject(bucket, ossKey);
            return objectStat != null;
        } catch (InsufficientDataException | InternalException | InvalidBucketNameException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException e) {
            throw new MinioAdapterException(e.toString(), e);
        } catch (ErrorResponseException e) {
            //文件不存在
            return false;
        }
    }


    @Override
    public InputStream downloadFile(OssBaseProperties ossBaseProperties, String bucket, String ossKey) {
        MinioClient minioClient = getMinioClient(ossBaseProperties, null);
        try {
            return minioClient.getObject(bucket, ossKey);
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidBucketNameException |
                 InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException |
                 XmlParserException e) {
            throw new MinioAdapterException(e.toString(), e);
        }
    }

}
